#pragma once
#include <memory>
#include <string>
#include "RI.h"
#include "Grid.h"
#include "MVoperator.h"
#include "Cycle.h"

using namespace std;

MatrixVectorOperator M;

class Solver
{
private:
    int N;
    vector<double> initv, F;
    string bc, cycle;
    unique_ptr<InterpolationOperator> I;
    unique_ptr<RestrictionOperator> R;
public:
    vector<double> v, Re;
    Solver(int N, Function &f, vector<double> initv, string bc, string ro, string io, string cycle) : N(N), initv(initv), bc(bc), cycle(cycle) 
    {
	// 初始化 InterpolationOperator 和 RestrictionOperator
        if (ro == "FullWeight") {
            R = make_unique<FullWeightingRestrictionOperator>();
        } else if (ro == "Injection") {
            R = make_unique<InjectionRestrictionOperator>();
        } else {
            cout << "RestrictionOperator error!" << endl;
	    exit(0);
        }

        if (io == "Linear") {
            I = make_unique<LinearInterpolationOperator>();
        } else if (io == "Quadratic") {
            I = make_unique<QuadraticInterpolationOperator>();
        } else {
            cout << "InterpolationOperator error!" << endl;
	    exit(0);
        }
	Grid grid1D(1, N); //1维N区间网格
	vector<double> x = grid1D.grid1D;
	F = f(x);
    };
    vector<double> solve(double a, double b, int iter, double epsilon)
    {
	vector<double> f(N-1);
	v.resize(N-1);
	if (bc == "D")
	{
	    f[0] = N*N*a;
	    f[N-2] = N*N*b;
	}
	else if (bc == "N")
	{
	    f[0] = -N*a - F[0]/2;
	    f[N-2] = -N*b + F[N]/2;
	}
	else if (bc == "M_DN")
	{
	    f[0] = N*N*a;
	    f[N-2] = -N*b + F[N]/2;
	}
	else if (bc == "M_ND")
	{
	    f[0] = -N*a - F[0]/2;
	    f[N-2] = N*N*b;
	}
	else
	{
	    cout << "bc error!" << endl;
	    exit(0);
	}
	for (int i = 1; i < N; i++)
	{
	    f[i-1] += F[i];	
	}
	Cycle Cycle(I.get(), R.get());
	int i = 1;
	
	while (i < iter && M.max_norm(f,M.M_times_V(M.get_A(N),v)) > epsilon)
	{
	    Re.push_back(M.max_norm(f,M.M_times_V(M.get_A(N),v)));
	    if (cycle == "V-cycle" || i > 1)
	    {
		v = Cycle.Vcycle(initv,f);
	    }
	    else if (cycle == "FMG")
	    {
		v = Cycle.FMG(initv,f);
	    }
	    else
	    {
		cout << "cycle type error!" << endl;
		exit(0);
	    }
	    i++;
	}
	return v;
    };
};
